package miniprojet.jeux.stateless;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import miniprojet.jeux.modele.Administrateur;
import miniprojet.jeux.modele.Arbitre;
import miniprojet.jeux.modele.But;
import miniprojet.jeux.modele.Equipe;
import miniprojet.jeux.modele.Etat;
import miniprojet.jeux.modele.Joueur;
import miniprojet.jeux.modele.Match;
import miniprojet.jeux.modele.Personne;
import miniprojet.jeux.modele.Tour;

@Stateless
public class TournoiBean implements TournoiLocal, TournoiRemote {

	@PersistenceContext(unitName = "monUnite")
	EntityManager em;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void peupler() {
		// Admin.
		Administrateur admin = new Administrateur();
		admin.setNom("ADMIN");
		admin.setPrenom("Admin");
		admin.setLogin("admin");
		admin.setPassword("admin");
		em.persist(admin);

		// Arbitres.
		List<Arbitre> arbitres = new ArrayList<Arbitre>();
		for (int i = 1; i <= 8; ++i) {
			Arbitre arbitre = new Arbitre();
			arbitre.setNom("ARBITRE" + i);
			arbitre.setPrenom("Arbitre" + i);
			arbitres.add(arbitre);
			em.persist(arbitre);
		}

		// Tour1.
		Tour tour = new Tour();
		tour.setNumero(1);
		Equipe eq1 = null;
		Equipe eq2 = null;
		int nMatch = 0;
		List<Match> matchs = new ArrayList<Match>();
		for (int i = 1; i <= 8; ++i) {
			Equipe equipe = new Equipe();
			equipe.setNom("Equipe" + i);
			// Représentant.
			Personne personne = new Personne();
			personne.setNom("PERSONNE" + i);
			personne.setPrenom("Personne" + i);
			em.persist(personne);
			equipe.setRepresentant(personne);
			equipe.setNumero(i); // Joueurs.
			for (int j = 1; j <= 11; ++j) {
				Joueur joueur = new Joueur();
				joueur.setNom("JOUEUR" + i + '-' + j);
				joueur.setPrenom("Joueur" + i + '-' + j);
				joueur.setEquipe(equipe);
				em.persist(joueur);
				equipe.addJoueur(joueur);
			}
			em.persist(equipe);
			if ((i - 1) % 2 == 0) {
				eq1 = equipe;
			} else {
				nMatch += 1;
				eq2 = equipe;
				Match match = new Match();
				matchs.add(match);
				match.setArbitre(arbitres.remove((int) (Math.random() * arbitres
						.size())));
				match.setEquipe1(eq1);
				match.setEquipe2(eq2);
				match.setNumero(nMatch);

				// Buts.
				int buts1 = (int) (Math.random() * 3);
				int buts2 = (int) (Math.random() * 3);
				if (buts1 == buts2) {
					buts1++;
				}
				List<Joueur> joueurs = (List<Joueur>) eq1.getJoueurs();
				Collection<But> buts = match.getButs();
				for (int m = 0; m < buts1; ++m) {
					But but = new But();
					but.setAuteur(joueurs.get((int) (Math.random() * joueurs
							.size())));
					but.setMinute((int) (Math.random() * 120));
					em.persist(but);
					buts.add(but);
				}
				joueurs = (List<Joueur>) eq2.getJoueurs();
				for (int m = 0; m < buts2; ++m) {
					But but = new But();
					but.setAuteur(joueurs.get((int) (Math.random() * joueurs
							.size())));
					but.setMinute((int) (Math.random() * 120));
					em.persist(but);
					buts.add(but);
				}
				match.setIdEquipeGagnante(buts1 > buts2 ? eq1.getIdEquipe()
						: eq2.getIdEquipe());
				// Prolongations/Tirs au but.
				match.setProlongations(Math.random() > 0.25f);
				if (match.nbButEquipe1() == match.nbButEquipe2())
					match.setTirsAuButs(true);
				match.setEtat(Etat.Termine);
				em.persist(match);
				tour.addMatch(match);
			}
		}
		em.persist(tour);

		// Tour2.
		tour = new Tour();
		tour.setNumero(2);
		// Matchs.
		nMatch = 0;
		while (!matchs.isEmpty()) {
			Match m1 = matchs.remove(0);
			Match m2 = matchs.remove(0);
			Match m = new Match();
			m.setNumero(nMatch);
			m.setEquipe1(m1.getIdEquipeGagnante() == m1.getEquipe1()
					.getIdEquipe() ? m1.getEquipe1() : m1.getEquipe2());
			m.setEquipe2(m2.getIdEquipeGagnante() == m2.getEquipe1()
					.getIdEquipe() ? m2.getEquipe1() : m2.getEquipe2());
			m.setEtat(Etat.Prevu);
			em.persist(m);
			tour.addMatch(m);
			++nMatch;
		}
		em.persist(tour);

	}

	public void demarrerTournoi() {
		ArrayList<Equipe> equipes = (ArrayList<Equipe>) getAllEquipes();
		if (equipes.size() == 2 || equipes.size() == 4 || equipes.size() == 8
				|| equipes.size() == 16 || equipes.size() == 32) {
			ArrayList<Integer> numeros = new ArrayList<Integer>();
			for (int i = 1; i < equipes.size(); i++) {
				numeros.add(i);
			}
			for (Equipe e : equipes) {
				Integer num = numeros.get((int) (Math.random() * (numeros
						.size() - 1)));
				e.setNumero(num);
				em.merge(e);
			}

			Tour premierTour = new Tour();
			premierTour.setNumero(1);
			Collections.sort(equipes, new Comparator<Equipe>() {

				@Override
				public int compare(Equipe o1, Equipe o2) {
					if (o1.getNumero() < o2.getNumero())
						return -1;
					else if (o1.getNumero() == o2.getNumero())
						return 0;
					else
						return 1;
				}
			});
			int numMatch = 1;
			for (int i = 0; i < equipes.size(); i += 2) {
				Match m = new Match();
				m.setEquipe1(equipes.get(i));
				m.setEquipe2(equipes.get(i + 1));
				m.setNumero(numMatch);
				em.persist(m);
				++numMatch;
				premierTour.addMatch(m);
			}

			em.persist(premierTour);
		}
	}

	@Override
	public void addJoueur(Joueur joueur) {
		em.persist(joueur);
	}

	@Override
	public void addEquipe(Equipe equipe) {
		em.persist(equipe);
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<Equipe> getAllEquipes() {
		Collection<Equipe> collec = em.createQuery("From Equipe e")
				.getResultList();
		return collec;
	}

	@Override
	public void addArbitre(Arbitre arbitre) {
		em.persist(arbitre);
	}

	@Override
	public Equipe getEquipeByName(String nom) {
		return em.find(Equipe.class, nom);
	}

	@Override
	public Collection<Joueur> getAllJoueursByEquipe(String nomEquipe) {
		// methode pas v�rifi�
		Query query = em
				.createQuery("select e.idEquipe From Equipe e where e.nom=:nomEquipe");
		int idEq = (int) query.getFirstResult();
		Collection<Joueur> collec = em.createQuery(
				"From Joueur j where j.idEquipe=:idEq").getResultList();
		return collec;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<Tour> getTours() {
		Collection<Tour> collec = em.createQuery("From Tour t").getResultList();
		return collec;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Collection<Tour> getToursDesc() {
		Collection<Tour> collec = em.createQuery(
				"From Tour t ORDER BY t.numero DESC").getResultList();
		for (Tour t : collec) {
			for (Match m : t.getMatchs()) {
				m.getButs().size();
			}
		}
		return collec;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Match getMatch(int id) {
		Query q = em.createQuery("From Match m WHERE m.idMatch=:id");
		q.setMaxResults(1);
		q.setParameter("id", id);
		Match m = (Match) q.getSingleResult();
		m.getButs().size();
		m.getEquipe1().getJoueurs().size();
		m.getEquipe2().getJoueurs().size();
		return m;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Equipe getEquipe(int id) {
		Query q = em.createQuery("From Equipe e WHERE e.idEquipe=:id");
		q.setMaxResults(1);
		q.setParameter("id", id);
		Equipe e = (Equipe) q.getSingleResult();
		e.getJoueurs().size();
		return e;
	}

	@Override
	public Administrateur authentifierAdministrateur(String login, String pwd) {
		Query q = em
				.createQuery("From Administrateur a WHERE a.login=:login AND a.password=:password");
		q.setMaxResults(1);
		q.setParameter("login", login);
		q.setParameter("password", pwd);
		try {
			Administrateur a = (Administrateur) q.getSingleResult();
			return a;
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public Collection<Arbitre> getAllArbitres() {
		Collection<Arbitre> collec = em.createQuery("From Arbitre a")
				.getResultList();
		return collec;
	}

	@Override
	public Arbitre getArbitre(int id) {
		return em.find(Arbitre.class, id);
	}

	@Override
	public void setArbitre(Arbitre arbitre) {
		em.merge(arbitre);
	}

	@Override
	public void deleteArbitre(int id) {
		Arbitre a = getArbitre(id);
		em.remove(a);
	}

	@Override
	public void setMatch(Match match) {
		em.merge(match);
	}

	@Override
	public Joueur getJoueur(int id) {
		return em.find(Joueur.class, id);
	}

	@Override
	public void addBut(But but, Match match) {
		em.persist(but);
		match.addBut(but);
		if (but.getMinute() > 90)
			match.setProlongations(true);
		setMatch(match);
	}

	@Override
	public boolean isDernierTourFini() {
		boolean fini = false;
		Collection<Tour> tours = getToursDesc();
		if (tours != null && tours.size() > 0) {
			Tour dernierTour = tours.iterator().next();
			if (dernierTour.getMatchs() != null
					&& dernierTour.getMatchs().size() > 0) {
				boolean pasFini = false;
				for (Match m : dernierTour.getMatchs()) {
					if (m.getEtat() != Etat.Termine) {
						pasFini = true;
						break;
					}
				}
				if (!pasFini)
					fini = true;
			} else {
				fini = true;
			}
		} else {
			fini = true;
		}
		return fini;
	}

	@Override
	public void nouveauTour() {
		if (isDernierTourFini()) {
			Collection<Tour> tours = getToursDesc();
			if (tours != null && tours.size() > 0) {
				Tour dernierTour = tours.iterator().next();
				em.merge(dernierTour);
				// si 1 match alors tournoi terminé
				if (dernierTour.getMatchs() != null
						&& dernierTour.getMatchs().size() > 1) {
					ArrayList<Equipe> equipesRestantes = new ArrayList<Equipe>();
					for (Match m : dernierTour.getMatchs()) {
						if (m.getIdEquipeGagnante() == m.getEquipe1()
								.getIdEquipe()) {
							equipesRestantes.add(m.getEquipe1());
						} else {
							equipesRestantes.add(m.getEquipe2());
						}
					}
					Collections.sort(equipesRestantes,
							new Comparator<Equipe>() {

								@Override
								public int compare(Equipe o1, Equipe o2) {
									if (o1.getNumero() < o2.getNumero())
										return -1;
									else if (o1.getNumero() == o2.getNumero())
										return 0;
									else
										return 1;
								}
							});
					Tour nouveauTour = new Tour();
					nouveauTour.setNumero(dernierTour.getNumero() + 1);
					int numMatch = 1;
					for (int i = 0; i < equipesRestantes.size(); i += 2) {
						Match nouveauMatch = new Match();
						nouveauMatch.setNumero(numMatch);
						nouveauMatch.setEquipe1(equipesRestantes.get(i));
						nouveauMatch.setEquipe2(equipesRestantes.get(i + 1));
						em.persist(nouveauMatch);
						nouveauTour.addMatch(nouveauMatch);
					}
					em.persist(nouveauTour);
				}
			}
		}
	}

	@Override
	public Collection<Arbitre> getAllArbitresDisponible() {
		try {
			Collection<Arbitre> collec = em
					.createQuery(
							"From Arbitre a "
									+ "WHERE a.idPersonne NOT IN(SELECT m.arbitre.idPersonne FROM Match m WHERE m.etat != 'Termine' AND m.arbitre != null)")
					.getResultList();
			// + "WHERE a.idPersonne != -1").getResultList();
			return collec;
		} catch (Exception e) {
			System.out.println(e.toString());
			return new ArrayList<Arbitre>();
		}
	}

	public void addRepresentant(Personne representant) {
		em.persist(representant);
	}

	@Override
	public void removeBut(Match match, int idBut) {
		But b = em.find(But.class, idBut);
		match.removeBut(b);
		if (match.isProlongations()) {
			boolean aucunButApres90 = true;
			for (But butRestants : match.getButs()) {
				if (butRestants.getMinute() > 90) {
					aucunButApres90 = false;
					break;
				}
			}
			if (aucunButApres90) {
				match.setProlongations(false);
			}
		}
		setMatch(match);

		em.remove(b);
	}
}
